package com.fishery.authority.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fishery.authority.client.BaseClient;
import com.fishery.authority.entity.*;
import com.fishery.authority.entity.vo.CreateBaseVo;
import com.fishery.authority.mapper.UserMapper;
import com.fishery.authority.service.*;
import com.fishery.authority.utils.SecurityContextUtil;
import com.fishery.entity.GlobalException;
import com.fishery.entity.Result;
import com.fishery.entity.StatusCode;
import com.fishery.util.MD5;
import io.swagger.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 控制器层
 *
 * @author Administrator
 */
@Api(description = "管理管理员相关接口")
@RestController
@CrossOrigin
@RequestMapping("/admin")
public class AdminController {


    @Autowired
    private UserService userService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private FunctionService functionService;

    @Autowired
    private BaseClient baseClient;

    @Autowired
    private UserRoleService userRoleService;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RoleBaseService roleBaseService;

    @Autowired
    private FunctionRoleService functionRoleService;

    /**
     * 查询全部管理员数据
     *
     * @return
     */
    @ApiOperation("查询全部管理员接口")
    @PreAuthorize("hasAnyAuthority('authority')")
    @RequestMapping(value = "/admin", method = RequestMethod.GET)
    public Result findAllAdmin() {
        return Result.success("查询成功").data(userService.findAllAdmin());
    }


    /**
     * 根据ID查询管理员
     *
     * @param id ID
     * @return
     */
    @ApiImplicitParam(paramType = "path", name = "id", value = "userID", required = true, dataType = "String")
    @ApiOperation("根据id查询管理员接口")
    @PreAuthorize("hasAnyAuthority('authority')")
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public Result findById(@PathVariable String id) {
        return Result.success("查询成功").data(userService.findAdminByUserId(id));
    }


    /**
     * 增加管理员
     *
     * @param user
     */
    @ApiOperation("新增管理员接口")
    @PreAuthorize("hasAnyAuthority('authority_admin_add')")
    @RequestMapping(method = RequestMethod.POST)
    public Result add(@RequestBody User user) {
        user.setIsAdmin(1);
        user.setPassword(MD5.encrypt(user.getPassword()));

        userService.save(user);
        return Result.success("增加成功");
    }


    /**
     * 删除
     *
     * @param id
     */
    @ApiOperation("删除管理员接口")
    @ApiImplicitParam(paramType = "path", name = "id", value = "管理员ID", required = true, dataType = "String")
    @PreAuthorize("hasAnyAuthority('authority_admin_delete')")
    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    public Result delete(@PathVariable String id) {
        if(id == null) {
            return Result.error("请输入id");
        }
        boolean ret = userService.removeById(id);
        return ret ? Result.success("删除成功") : Result.error("删除失败，请检查无误后再试");
    }

    /**
     * 查询可添加的角色
     */
    @ApiOperation("查询可给该管理员添加的角色")
    @ApiImplicitParam(paramType = "path", name = "userId", value = "管理员ID", required = true, dataType = "String")
    @PreAuthorize("hasAnyAuthority('authority_admin')")
    @RequestMapping(value = "/otherRole/{userId}", method = RequestMethod.GET)
    public Result findOthers(@PathVariable String userId) {
        return Result.success("查找角色成功").data(roleService.findOthersByUserId(userId));
    }

    /**
     * 查询已拥有的角色
     */
    @ApiOperation("查询该管理员已拥有的角色")
    @ApiImplicitParam(paramType = "path", name = "userId", value = "管理员ID", required = true, dataType = "String")
    @PreAuthorize("hasAnyAuthority('authority_admin')")
    @RequestMapping(value = "/role/{userId}", method = RequestMethod.GET)
    public Result findRoles(@PathVariable String userId) {
        return Result.success("查找角色成功").data(roleService.findRoleByUserId(userId));
    }

    /**
     * 查询已拥有的权限
     */
    @ApiOperation("查询该管理员已拥有的权限")
    @RequestMapping(value = "/authority", method = RequestMethod.GET)
    public Result findAuthority() {
        UserDetailsImpl user = SecurityContextUtil.getUserDetails();

        return Result.success("查找权限成功").data(functionService.grand(functionService.findByUserId(user.getId())));
    }

    /**
     * 查询在某一模块中已拥有的权限
     */
    @ApiOperation("查询在某一模块中已拥有的权限")
    @RequestMapping(value = "/authority/{module}", method = RequestMethod.GET)
    public Result findAuthorityBy(@PathVariable String module) {
        UserDetailsImpl user = SecurityContextUtil.getUserDetails();
        List<FunctionParent> functionList = functionService.grand(functionService.findByUserId(user.getId()));
        List<FunctionParent> functionListInModule = new ArrayList<>();

        // 将不符合的去掉
        for(FunctionParent function: functionList){
            if(function.getName().startsWith(module)){
                functionListInModule.add(function);
            }
        }

        return Result.success("查找权限成功").data(functionListInModule);
    }


    /**
     * 更新管理员角色
     *
     * @param userId
     * @param roleIdList
     * @return
     */
    @ApiOperation("超级管理员更新管理员角色接口")
//    @ApiImplicitParams({
//            @ApiImplicitParam(paramType = "path", name = "userId", value = "管理员ID", required = true, dataType = "String"),
//            @ApiImplicitParam(paramType = "body", name = "roleIdList", value = "{\"roleIdList\": [\"roleId1\", \"roleId2\"]}", dataType = "Map")
//    })
    @PreAuthorize("hasAnyAuthority('authority_admin_updateRole')")
    @RequestMapping(value = "/{userId}", method = RequestMethod.POST)
    public Result updateRoleOfUser(@PathVariable String userId, @RequestBody Map roleIdList) {
        userService.UpdateRoleOfAdmin(userId, roleIdList);
        return Result.success("更新管理员角色成功");
    }


    /**
     * 超级管理员修改普通管理员
     *
     * @param user
     * @param
     * @return
     */

    @ApiOperation("修改普通管理员基本信息接口")
    @PreAuthorize("hasAnyAuthority('authority_admin_update')")
    @RequestMapping(value = "/admin/update", method = RequestMethod.PUT)
    public Result updateUser(@RequestBody User user) {
        user.setIsAdmin(1);
        userService.updateUser(user);
        return Result.success("修改成功");
    }

    /**
     * 分页查询管理员接口
     *
     * @param current      页码
     * @param size      页大小
     * @return 分页结果
     */
    @ApiOperation("分页查询管理员接口")
//    @ApiImplicitParams({
//            @ApiImplicitParam(paramType = "path", name = "current", value = "页面", dataType = "Integer"),
//            @ApiImplicitParam(paramType = "path", name = "size", value = "尺寸", dataType = "Integer")
//    })
    @PreAuthorize("hasAnyAuthority('authority_admin')")
    @RequestMapping(value = "/search/{current}/{size}", method = RequestMethod.POST)
    public Result findSearch(@PathVariable int current,
                             @PathVariable int size) {
        size = size <= 0 ? 5 : size;
        current = current <= 0 ? 1 : current;
        Page<User> page = new Page(current, size);
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.orderByDesc("gmt_create");
        userService.page(page, wrapper);
        return Result.success().data(page);
    }


    /**
     * 更新基地管理员
     *
     * @param userId
     * @param baseId
     * @return
     */
    @ApiOperation("更新基地管理员接口")
//    @ApiImplicitParams({
//            @ApiImplicitParam(paramType = "path", name = "userId", value = "用户id", required = true, dataType = "String"),
//            @ApiImplicitParam(paramType = "path", name = "baseId", value = "基地id", required = true, dataType = "String"),
//            @ApiImplicitParam(paramType = "path", name = "baseIdentity", value = "权限", dataType = "Integer")
//    })
    @PreAuthorize("hasAnyAuthority('authority')")
    @RequestMapping(value = "/update/{userId}/{baseId}/{baseIdentity}", method = RequestMethod.PUT)
    public Result updateBaseAdmin(@PathVariable String userId, @PathVariable String baseId, @PathVariable int baseIdentity) {
        userService.updateBaseAdmin(userId, baseId, baseIdentity);

        Map message = (Map)redisTemplate.opsForValue().get("baseMessage");
        message.remove(userId);
        redisTemplate.opsForValue().set("baseMessage", message);

        return Result.success("更新成功");
    }

    /**
     * 拒绝更新基地管理员接口
     * @param userId
     * @return
     */
    @ApiOperation("拒绝更新基地管理员接口")
    @ApiImplicitParam(paramType = "path", name = "userId", value = "用户id", required = true, dataType = "String")
    @PreAuthorize("hasAnyAuthority('authority')")
    @RequestMapping(value = "/rejectUpdate/{userId}", method = RequestMethod.PUT)
    public Result rejectUpdateBaseAdmin(@PathVariable String userId){
        Map message = (Map)redisTemplate.opsForValue().get("baseMessage");
        message.remove(userId);
        redisTemplate.opsForValue().set("baseMessage", message);

        return Result.success("拒绝成功");
    }

    /**
     * 管理员获取当前申请成为基地管理员的信息
     *
     * @return
     */
    @ApiOperation("获取当前申请成为基地管理员的信息")
    @PreAuthorize("hasAnyAuthority('authority')")
    @RequestMapping(value = "/message/detail", method = RequestMethod.GET)
    public Result findMessage(){
        Map message = (Map)redisTemplate.opsForValue().get("baseMessage");
        return Result.success("查询成功").data(message);
    }

    /**
     * 管理员获取当前申请成为基地管理员的数量
     *
     * @return
     */
    @ApiOperation("获取当前申请成为基地管理员的数量")
    @PreAuthorize("hasAnyAuthority('authority')")
    @RequestMapping(value = "/message/number", method = RequestMethod.GET)
    public Result findMessageNum(){
        Map message = (Map)redisTemplate.opsForValue().get("baseMessage");
        return new Result(true, StatusCode.OK, "查询成功", message == null ? 0 : message.size());
    }

    @ApiOperation(value = "删除基地")
    @PreAuthorize("hasAnyAuthority('enterprise_enterprise_delete')")
    @RequestMapping(value = "/base/{baseId}", method = RequestMethod.DELETE)
    public Result delBase(@PathVariable String baseId){
        return userService.delBase(baseId);
    }

    @ApiOperation(value = "根据基地ID查询用户")
    @RequestMapping(value = "/user/{baseId}",method = RequestMethod.GET)
    public Result getUserByBaseId(@PathVariable String baseId){
        List<User> users = null;
        try{
            users = userService.getUserByBaseId(baseId);
        }catch (Exception e){
            throw new GlobalException(new Result(false, StatusCode.ERROR, "获取用户信息失败,"+e.getMessage(), null));
        }
        return Result.success("获取用户成功").data(users);
    }

    /**
     * 新增基地
     *
     * @param userId
     * @param vo
     * @return
     */
    @ApiOperation("新增基地接口")
    @RequestMapping(value = "/addBase/{userId}", method = RequestMethod.POST)
    @Transactional
    @Async
    public Result updateBaseAdmin(@PathVariable String userId, @RequestBody CreateBaseVo vo) {
        if(StringUtils.isEmpty(userId)) {
            return Result.error("请输入userId");
        }
        //根据传过来的userId查到对应用户
        User user = userService.getById(userId);
        //判断用户非空
        if(user.equals(null)) {
            return Result.error("查无此用户");
        }
        //判断用户是否已经创建基地，是则直接报错
        String baseId = user.getBaseId();
        if(!StringUtils.isEmpty(baseId)) {
            return Result.error("该用户已有基地，请勿重复操作");
        }
        //如果用户无基地，开始异步创建基地流程
        //从联调的创建基地接口拿到返回的信息
        Result result = baseClient.createBase(vo);
        //如果创建基地成功，执行下列操作，失败则报错
        if (result.getStatusCode() == 20000) {
            //从联调的创建基地接口拿到新创建的基地id
            String newBaseId = (String) result.getData();
            //从创建基地的信息里拿到到redis查询所对应要打的权限的key
            String redisKey = getRedisKey(vo.getTypes());
            //拿到权限id集合
            List<String> functionIdList = (List<String>) redisTemplate.opsForHash().get("FUNCTION_ID", redisKey);
            //新建角色，封装信息后保存到t_authority_role
            Role role = new Role();
            role.setName("boss");
            role.setRemarks("boss");
            role.setUseable(true);
            //拿到t_authority_role保存结果
            boolean role_Ret = roleService.save(role);
            String roleId = role.getId();
            //验证是否成功
            if(!role_Ret) {
                return Result.error("插入新角色失败");
            }
            //封装构造体，删去t_authority_user_role中该用户的所有记录
            QueryWrapper wrapper = new QueryWrapper();
            wrapper.eq("user_id", userId);
            //拿到t_authority_user_role删除结果
            boolean removeUserRole_Ret = userRoleService.remove(wrapper);
            if(!removeUserRole_Ret) {
                return Result.error("删除原有用户角色失败");
            }
            //新建用户角色对象，封装信息后保存到t_authority_user_role
            UserRole userRole = new UserRole();
            userRole.setUserId(userId);
            userRole.setRoleId(roleId);
            //拿到保存到t_authority_user_role的结果
            boolean userRole_Ret = userRoleService.save(userRole);
            if(!userRole_Ret) {
                return Result.error("新增用户角色失败");
            }
            //新建RoleBase对象，封装信息后保存到t_authority_role_base
            RoleBase roleBase = new RoleBase();
            roleBase.setRoleId(roleId);
            roleBase.setBaseId(newBaseId);
            //拿到保存到t_authority_role_base的结果
            boolean roleBase_Ret = roleBaseService.save(roleBase);
            //对上述操作的结果进行查验，如果失败则返回报错
            if(!roleBase_Ret) {
                return Result.error("插入基地角色失败");
            }
            //循环拿到从redis拿到的权限id集合
            for(String functionId : functionIdList) {
                //新建权限角色集合，封装数据，保存，拿到结果，查验是否成功
                FunctionRole functionRole = new FunctionRole();
                functionRole.setRoleId(roleId);
                functionRole.setFunctionId(functionId);
                boolean functionRole_Ret = functionRoleService.save(functionRole);
                if(!functionRole_Ret) {
                    return Result.error("插入角色权限失败");
                }
            }
            //更新用户信息中的基地和基地角色并保存查验
            user.setBaseId(newBaseId);
            user.setBaseIdentity(2);
            return userService.updateById(user) ? Result.success("保存成功") : Result.error("保存失败");
        }
        return Result.error("执行出错");
    }

    private String getRedisKey(List<String> types) {
        StringBuffer typesStr = new StringBuffer();
        types.sort((s1, s2) -> s1.charAt(0) - s2.charAt(0));
        types.forEach(type -> typesStr.append(type));
        String s = types.toString();
        System.out.println(s);
        return types.toString();
    }

    /**
     * 修改基地类型，修改对应权限
     *
     * @param baseId
     * @param oldBaseTypes
     * @param newBaseTypes
     * @return
     */
    @ApiOperation("修改基地类型，修改对应权限")
    @Transactional
    @RequestMapping(value = "/updateBaseTypes/{baseId}/{oldBaseTypes}/{newBaseTypes}", method = RequestMethod.POST)
    public Result updateBaseAdmin(@PathVariable(name = "baseId") @ApiParam(required = true, value = "基地id") String baseId,
                                  @PathVariable(name = "oldBaseTypes") @ApiParam(required = true, value = "原基地类型") String oldBaseTypes,
                                  @PathVariable(name = "newBaseTypes") @ApiParam(required = true, value = "新基地类型") String newBaseTypes) {
        String userId = SecurityContextUtil.getUserDetails().getId();
        QueryWrapper<UserRole> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        UserRole userRole = userRoleService.getOne(wrapper);
        String roleId = userRole.getRoleId();
        List<String> oldFunctionIdList = (List<String>) redisTemplate.opsForHash().get("FUNCTION_ID", oldBaseTypes);
        List<String> newFunctionIdList = (List<String>) redisTemplate.opsForHash().get("FUNCTION_ID", newBaseTypes);
        newFunctionIdList.removeAll(oldFunctionIdList);
        for (String functionId : newFunctionIdList) {
            FunctionRole functionRole = new FunctionRole();
            functionRole.setFunctionId(functionId);
            functionRole.setRoleId(roleId);
            boolean save = functionRoleService.save(functionRole);
            if(!save) {
                return Result.error();
            }
        }
        return Result.success();
    }
}